#pragma once

#ifndef __M_UTIL_H__
#define __M_UTIL_H__

#include <iostream>
#include <sys/stat.h>
#include <fstream>
#include <experimental/filesystem>

/*
    1.提供获取文件大小的接口
    2.提供获取文件最近修改时间和访问时间的接口
    3.获取文件的大小
    4.获取文件名称
    5.判断文件是否存在
    6.在文件系统删除某个文件
    7.获取文件pos位置开始，长度为len的文件内容
    8.获取整个文件的内容
    9.往文件写入内容
    10.创建目录
    11.获取该目录下的所有文件
*/

namespace cloud
{
    namespace fs = std::experimental::filesystem; // c++17新增加的库
    class FileUtil
    {
    private:
        std::string _filename;

    public:
        FileUtil(const std::string filename)
            : _filename(filename)
        {
        }

        bool Remove() // 在文件系统里清除名字为_filename的文件
        {
            if (IsExist() == false) // 不存在
            {
                std::cout << _filename << "is not exist" << std::endl;
                return false;
            }
            remove(_filename.c_str());
            return true;
        }

        time_t FileLastATime() // 文件的atime,即最后访问时间
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                std::cerr << "get file atime fail" << std::endl;
                return -1;
            }
            return st.st_atime;
        }

        time_t FileLastMTime() // 获取文件最后修改的时间
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                std::cerr << "get file mtine fail" << std::endl;
                return -1;
            }
            return st.st_mtime;
        }

        int64_t FileSize() // 获取文件的大小
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                std::cerr << "get file size fail" << std::endl;
                return -1;
            }
            return st.st_size;
        }
        std::string FileName()
        {
            auto pos = _filename.find_last_of("/\\"); // ‘/’是linux下的文件分隔符,"\"是windows的文件分隔符,"\\"地提高\防止第二个被识别为其他
            if (pos == std::string::npos)
            {
                return _filename;
            }
            return _filename.substr(pos + 1); // 从'/'或者'\'开始切割
        }

        bool GetPosLen(std::string* str, size_t pos, size_t len) // 从pos位置开始获取长度为len的文件内容
        {
            size_t filesize = FileSize();
            if (pos + len > filesize) // 判断获取长度是否超过文件的大小
            {
                std::cerr << "get file len is error" << std::endl;
                return false;
            }
            std::ifstream ifs;
            ifs.open(_filename, std::ios::binary); // 打开文件
            if (ifs.is_open() == false)
            {
                std::cerr << "open file fail" << std::endl;
                return false;
            }
            ifs.seekg(pos, std::ios::beg); // 从文件开始,将文件指针移动pos位置
            str->resize(len);
            ifs.read(&(*str)[0], len); // 读取到str
            if (ifs.good() == false)
            {
                std::cerr << "read file fail" << std::endl;
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }

        bool GetContent(std::string* str) // 获取整个文件的内容
        {
            size_t len = FileSize();
            return GetPosLen(str, 0, len);
        }

        bool SetContent(const std::string& str)
        {
            std::ofstream ofs;
            ofs.open(_filename, std::ios::binary); // 打开文件
            if (ofs.is_open() == false)
            {
                std::cerr << "open file fail" << std::endl;
                return false;
            }
            ofs.write(&str[0], str.size()); // 往文件写入内容
            if (ofs.good() == false)
            {
                std::cerr << "write into file fail" << std::endl;
                ofs.close();
                return false;
            }
            ofs.close();
            return true;
        }

        bool IsExist() // 判断文件是否存在
        {
            return fs::exists(_filename);
        }

        bool CreatDictroy()//创建目录
        {
            if (IsExist()) return false;
            return fs::create_directories(_filename);
        }

        bool ScanDictory(std::vector<std::string>* arry)// 获取该目录下的所有文件
        {
            for (auto& p : fs::directory_iterator(_filename))//遍历该目录下的所有子目录和文件
            {
                if (fs::is_directory(p)) continue;//如果是目录,就跳过
                arry->push_back(fs::path(p).relative_path().string());//文件就进行存入
            }
            return true;
        }
    };
}

#endif

